package com.spdbcc.bili;

import lombok.val;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class SteamTest {

    private static List<Author> getAuthors() {
        //数据初始化
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);//两个对象属性相同认为对象相同，distinct会去重
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀划分了爱恨"));
        books1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述如何从失败中明悟真理"));

        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的恋爱观注定很难把他所在的时代理解"));

        books3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家  灵魂和肉体的碰撞会激起怎么样的火花呢？"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));
        return authorList;
    }

    public static void main(String[] args) {
        //testMap();

//        testDistinct();

//        testSorted();

//        testSkip();
        
        
//        testFlatmap();

//        testFlatmap2();

//        testMaxAndMin();

//        testCollectToList();
//
//        testCollectToSet();

//        testCollectToMap();


//        testAnyMatch();

//        testFindFirst();
        
//        testReduce01();

        testReduceMax();

        testReduceMin();



    }

    /**
     * Reduce qiu
     *
     */
    private static void testReduceMin() {
        Integer min = getAuthors().stream().distinct()
                .map(e -> e.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result < element ? result : element);
        System.out.println(min);
    }

    private static void testReduceMax() {

        Integer reduce = getAuthors().stream().distinct()
                .map(e -> e.getAge())
                .reduce(Integer.MIN_VALUE, (result, element) -> result > element ? result : element);
        System.out.println(reduce);
    }

    /**
     *  使用reduce求所有作者年龄的和
     */
    private static void testReduce01() {
        List<Author> authors = getAuthors();
        Integer sum = authors.stream()
                .distinct()
                .map(e->e.getAge())
                .reduce(0, new BinaryOperator<Integer>() {

                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result+element;
                    }
                });
        System.out.println("all author age:"+sum);
    }

    /**
     * 获取一个年龄最小的作家，并输出他的姓名。
     */
    private static void testFindFirst() {
        Optional<Author> authorOptional = getAuthors().stream().
                sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .findFirst();

        authorOptional.ifPresent(e-> System.out.println(e));
    }


    /**
     * anyMatch  判断是否存在复合条件的元素
     */
    private static void testAnyMatch() {
        boolean b = getAuthors().stream()
                .anyMatch(e -> e.getAge() > 30);
        System.out.println("是否存在大于30的元素："+b);
    }


    /**
     * 获取一个Map集合，map的key为作者名，value为List<Book>
     *
     * 通过工具类 Collectors.toMap 通过参数告知工具类怎么获取 key 怎么获取value
     */
    private static void testCollectToMap() {

        Map<String, List<Book>> map = getAuthors().stream()
                // Duplicate key [Book(id=5
                .distinct()
                .collect(Collectors.toMap(new Function<Author, String>() {

            @Override
            public String apply(Author author) {
                return author.getName();
            }
        }, new Function<Author, List<Book>>() {

            @Override
            public List<Book> apply(Author author) {
                return author.getBooks();
            }
        }));

        System.out.println(map);
    }

    /**
     * 获取一个所有书名的Set集合。
     */
    private static void testCollectToSet() {
        List<Author> authors = getAuthors();
        Set<String> collect = authors.stream().flatMap(e -> e.getBooks().stream())
                .map(e -> e.getName())
                .collect(Collectors.toSet());

        System.out.println("set :"+ collect);
    }

    /**
     * 获取一个所有书名的Set集合。
     */
    private static void testCollectToList() {
        List<Author> authors = getAuthors();
        List<String> stringList = authors.stream().flatMap(e -> e.getBooks().stream())
                .map(e -> e.getName())
                .distinct()
                .collect(Collectors.toList());

        System.out.println(stringList);
    }


    /**
     * 分别获取这些作家的所出书籍的最高分和最低分并打印。
     *
     * max min 获取到的是极大值还是极小值 注意传参的 comparator  表达式
     */
    private static void testMaxAndMin() {
        List<Author> authors = getAuthors();
        Optional integerOptional = authors.stream()
                .flatMap(e -> e.getBooks().stream())
                .map(e -> e.getScore())
                .max(new Comparator<Integer>() {
                    @Override
                    public int compare(Integer o1, Integer o2) {
                        // 极小值
                        // return o2 - o1;
                        return  o1-o2;
                    }
                });

        Optional<Integer> optionalMinInteger = authors.stream()
                .flatMap(e -> e.getBooks().stream())
                .map(e -> e.getScore())
                // 极大值
//                .min((score1, score2) -> score2 - score1);
                .min((score1, score2) -> score1 - score2);

        System.out.println( "max: "+integerOptional.get());;
        System.out.println( "min: "+optionalMinInteger.get());;

    }

    /**
     * 打印现有数据的所有分类。要求对分类进行去重。不能出现这种格式：哲学,爱情
     */
    private static void testFlatmap2() {
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(e->e.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(s -> System.out.println(s));
    }



    /**
     * 	map只能把一个对象转换成另一个对象来作为流中的元素。
     * 	而flatMap可以把【一个】对象转换成【多个】对象作为流中的元素。
     * 	对多个stream流的合并处理
     *
     * 	打印所有书籍的名字。要求对重复的元素进行去重。
     */
    private static void testFlatmap() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                // map 中把books list作为一个对象 相当于 addAll 把整个元素添加进流中了
                .map(e->e.getBooks())
                .forEach(e-> System.out.println(e));

        System.out.println("---------");

        authors.stream()

                .flatMap(new Function<Author, Stream<Book>>() {
                    // 把对象的list中的所有元素转换成流 添加到一个流中了
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                })
                .distinct()
                .forEach(new Consumer<Book>() {
                    @Override
                    public void accept(Book book) {
                        System.out.println(book.getName());
                    }
                });

        System.out.println("---------");
        authors.stream()

                .flatMap(author -> author.getBooks().stream()) .distinct().forEach(e-> System.out.println(e));

    }

    /**
     * 打印除了年龄最大的作家外的其他作家，要求不能有重复元素，并且按照年龄降序排序。
     */
    private static void testSkip() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .skip(1)
                .forEach(e-> System.out.println(e.getName()+e.getAge()));


    }

    /**
     * 	对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素,然后打印其中年龄【最大的两个】作家的姓名。
     */
    private static void testLimit() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .limit(2)
                .forEach(e-> System.out.println(e.getName()+e.getAge()));
    }

    private static void testSorted() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                // 排序时 sorted（）方法会把流中的元素转换成Comparable 元素为实现comparable则不能排序
                //  com.spdbcc.bili.Author cannot be cast to java.lang.Comparable
                //  对流中的元素 按年龄 降序
                .sorted()
                .forEach(e-> System.out.println(e.getName()+e.getAge()));
        System.out.println("---------");
        authors.stream()
                .distinct()
                // 这是升序
                .sorted((o1, o2) -> o1.getAge()-o2.getAge())
                .forEach(e-> System.out.println(e.getName()+e.getAge()));
    }


    private static void testDistinct() {
        List<Author> authors = getAuthors();
        authors.stream()
                //根据对象的equals和hashcode方法去重了
                .distinct()
                .forEach(e-> System.out.println(e.getName()));

        System.out.println("---------");
        authors.stream()
                .forEach(e-> System.out.println(e.getName()));
    }

    private static void testMap() {
        Map<String,Integer> map = new HashMap<>();
        map.put("蜡笔小新",19);
        map.put("黑子",17);
        map.put("日向翔阳",16);

        Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();

        stream.filter(new Predicate<Map.Entry<String, Integer>>() {
            @Override
            public boolean test(Map.Entry<String, Integer> stringIntegerEntry) {
                return stringIntegerEntry.getValue()>18;
            }
        }).forEach(new Consumer<Map.Entry<String, Integer>>() {
            @Override
            public void accept(Map.Entry<String, Integer> entry) {
                System.out.println(entry.getKey()+"---"+entry.getValue());
            }
        });

        List<Author> authors = getAuthors();
        authors.stream()
                //map 对流中的元素进行转换
                .map(x->x.getName())
                .forEach(e-> System.out.println(e));

        authors.stream()
                //map 对流中的元素进行转换
                .map(x->x.getAge())
                //map 对流中的元素进行计算
                .map(age->age+10)
                .forEach(integer -> System.out.println(integer));
    }
}
